// require
var fs = require("fs");
var xml2js = require("xml2js");
var util = require("util");

// functions

function findAspect(aspects, aspectName)
{
  var res;
  aspects.forEach(function(a)
    {
      res = a.$.name === aspectName ? a : null;
    });
  return res;
}

function findContraint(modelXML, constraintName)
{
  var constraints = modelXML.constraints ? modelXML.constraints[0].constraint : [];
  var res;
  constraints.forEach(function(c)
    {
      if(c.$.name === constraintName)
      {
        var parameters = c.parameter;
        parameters.forEach(function(param)
          {
            if(param.$.name === "allowedValues" &&
               param.list)
            {
              res = param.list[0].value;
            }
          });
      }
    });
  
  return res;
}

function buildProperty(modelXML, property)
{
  var constraints = property.constraints ? property.constraints[0].constraint : [];
  var res;
  constraints.forEach(function(c)
    {
      res = findContraint(modelXML, c.$.ref);
    });
  
  return res;
}

function buildPropertiesList(modelXML, asp)
{
  var properties = asp.properties ? asp.properties[0].property : [];
  var propertiesList = {};
  properties.forEach(function(p)
    {
      var propName = p.$.name;
      propertiesList[propName] = buildProperty(modelXML, p);
      
    });
  return propertiesList;
}

function buildAspectsList(modelXML, aspects)
{
  var aspectsList = {};
  
  aspects.forEach(function(a)
    {
      var aspectName = a.$.name;
      if(!aspectsList[aspectName])
      {
        var properties = buildPropertiesList(modelXML, a);
        aspectsList[aspectName] = properties;
      }
      var parentAspectName = a.parent ? a.parent[0] : null;
      if(parentAspectName)
      {
        var parentProperties = aspectsList[parentAspectName];
        if(!parentProperties)
        {
          var parentAspect = findAspect(aspects, parentAspectName);
          parentProperties = buildPropertiesList(modelXML, parentAspect);
          aspectsList[parentAspectName] = parentProperties;
        }
        
        for(prop in parentProperties)
        {
          aspectsList[aspectName][prop] = parentProperties[prop];
        }
      }
    });
  //console.log(util.inspect(aspectsList, false, null));
  return aspectsList;
}

function buildTypesList(modelXML, types, aspectsList)
{
  var typesList = {};
  types.forEach(function(t)
    {
      var typeName = t.$.name;
      console.log("Type", typeName);
      var typeJson = {};
      var mandatoryAspects = t["mandatory-aspects"] ? t["mandatory-aspects"][0].aspect : [];
      mandatoryAspects.forEach(function(ma)
        {
          var aspect = aspectsList[ma];
          for(prop in aspect)
          {
            typeJson[prop] = aspect[prop] ? aspect[prop] : null;
          }
        });
      typesList[typeName] = typeJson;
    });
  return typesList;
}

function saveToFile(typesList)
{
  var destinationPath = process.argv[3] || "json_file.json";
  console.log("Writing to file: ", destinationPath);
  var stringJson = JSON.stringify(typesList);
  var buff = new Buffer(stringJson);
  console.log("Buffer", buff.toString());
  fs.writeFileSync(destinationPath, buff);
}

function build(modelXML)
{
  var types = modelXML.types[0].type;
  var aspects = modelXML.aspects[0].aspect;
  
  var aspectsList = buildAspectsList(modelXML, aspects);
  var typesList = buildTypesList(modelXML, types, aspectsList);
  //console.log(util.inspect(typesList, false, null));
  
  saveToFile(typesList);
}

// body
var path = process.argv[2];// || (__dirname + '/prova.xml');

if(path)
{
  console.log("Reading from file: " + path);
  
  var parser = new xml2js.Parser();
  fs.readFile(path, function(err, data) {
      parser.parseString(data, function (err, result) {
          //console.log(util.inspect(result, false, null));
          console.log('Done');
          build(result.model);
      });
  });
}
else
{
  console.log("Usage:");
  console.log("node <js> pathToModel.xml [optional: pathToResult.json]");
}